#include "MyDb.hpp"

using namespace std;

MyDb::MyDb(std::string &path, std::string &dbName)
    : db_(NULL, 0),               // Instantiate Db object
      dbFileName_(path + dbName), // Database file name
      cFlags_(DB_CREATE)          // If the database doesn't yet exist,
                                  // allow it to be created.
{
    try
    {
        // Redirect debugging information to std::cerr
        db_.set_error_stream(&std::cerr);
                                                                                                                                    
        // Open the database
        db_.open(NULL, dbFileName_.c_str(), NULL, DB_BTREE, cFlags_, 0);
    }
    // DbException is not a subclass of std::exception, so we
    // need to catch them both.
    catch(DbException &e)
    {
        std::cerr << "Error opening database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    }
    catch(std::exception &e)
    {
        std::cerr << "Error opening database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    }
}

// Private member used to close a database. Called from the class
// destructor.
void
MyDb::close()
{
    // Close the db
    try
    {
        db_.close(0);
        std::cout << "Database " << dbFileName_
                  << " is closed." << std::endl;
    }
    catch(DbException &e)
    {
        std::cerr << "Error closing database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    }
    catch(std::exception &e)
    {
        std::cerr << "Error closing database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    }
} 

bool
MyDb::AddData(const string& MD5)
{
    bool status = true;
    try {
        Dbt key((char* )MD5.c_str(), MD5.length() + 1);
        char dump = '\0';       // just for store
        Dbt  data(&dump, sizeof(dump));
        int  ret  = db_.put(NULL, &key, &data, DB_NOOVERWRITE);

        if (ret == DB_KEYEXIST) {
            std::cerr << "Key already exist in " << dbFileName_ << "\n";
        }
    } catch(DbException  & e) {
        std::cerr << "Error adding data to  database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
        status = false;
    } catch(std::exception &e) {
        std::cerr << "Error adding data to  database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
        status = false;
    }
    
    return status;
}

bool
MyDb::RetrievalData(const string& MD5)
{
    bool is_in_db = false;

    try {
        Dbt key((char* )MD5.c_str(), MD5.length() + 1);
        char dump;                  // just for store
        Dbt data(&dump, sizeof(dump));
        int ret = db_.get(NULL, &key, &data, 0);
        if (ret != DB_NOTFOUND) {
            is_in_db = true;
        }
    } catch(DbException& e) {
        std::cerr << "Error retrieval data in database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    } catch(std::exception& e) {
        std::cerr << "Error retrieval data in database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
    }
    
    return is_in_db;
}

bool
MyDb::DelData(const string& MD5)
{
    bool status = true;

    try {
        Dbt key((char* )MD5.c_str(), MD5.length() + 1);
        db_.del(NULL, &key, 0);
    } catch(DbException& e) {
        std::cerr << "Error delete data in database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
        status = false;
    } catch(std::exception& e) {
        std::cerr << "Error delete data in database: " << dbFileName_ << "\n";
        std::cerr << e.what() << std::endl;
        status = false;
    }
    
    return status;
}
